#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>


// 响应SIGALRM信号
// 3. 闹钟到期后，SIGALRM信号递达
// 4. 内核返回用户态后，执行注册的sighandler处理信号
void sig_alarm() {
    printf("recv signal SIGALRM\n");
}

/* 演示sigaction如何使用 */
unsigned int mysleep(unsigned int nsecs) {
    struct sigaction newact, oldact; // 用于存储新、旧sigaction
    unsigned int uslept; // 剩余时间

    // 1.用户程序注册了信号处理函数sighandler
    newact.sa_handler = sig_alarm;
    sigemptyset(&newact.sa_mask);
    newact.sa_flags = 0; // 清除sa_flags

    sigaction(SIGALRM, &newact, &oldact);

    // 2.发送中断或异常切换到内核态
    alarm(nsecs); // 设置闹钟，nsecs秒后内核向进程发送SIGALRM信号
    pause(); // 阻塞进程

    // 5. sighandler返回后，自动执行特殊系统调用sigreturn再次进入内核态
    // 6.如果没有新信号要递达，再返回用户态就是恢复main继续执行
    uslept = alarm(0); // 获取上一次alarm剩余时间，如果没有剩余时间（已经捕获SIGALRM）则为0

    sigaction(SIGALRM, &oldact, NULL); // 恢复SIGALRM关联处理动作为原来的oldact

    return uslept;
}

int main() {
    while (1) {
        int seconds = 2;
        mysleep(seconds);
        printf("%d seconds passed\n", seconds);
    }
    return 0;
}

